home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / daemons / nfs / nfs-serv.2be / nfs-serv / nfs-server-2.2beta16 / auth_init.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-11  |  10.5 KB  |  465 lines

  1. /*
  2.  * auth_init.c    This module takes care of request authorization.
  3.  *
  4.  * Authors:    Donald J. Becker, <becker@super.org>
  5.  *        Rick Sladkey, <jrs@world.std.com>
  6.  *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  7.  *        Olaf Kirch, <okir@monad.swb.de>
  8.  *        Alexander O. Yuriev, <alex@bach.cis.temple.edu>
  9.  *
  10.  *        This software maybe be used for any purpose provided
  11.  *        the above copyright notice is retained.  It is supplied
  12.  *        as is, with no warranty expressed or implied.
  13.  */
  14.  
  15. #include "nfsd.h"
  16. #include "fakefsuid.h"
  17. #include <pwd.h>
  18.  
  19. #define LINE_SIZE    1024
  20. #define CHUNK_SIZE    1024    /* the 'typical' maximum line length    */
  21.  
  22. #ifndef EXPORTSFILE
  23. #define EXPORTSFILE    "/etc/exports"
  24. #endif
  25.  
  26. /* Support for file access control on /etc/exports by Alex Yuriev. */
  27. #include "faccess.h"
  28. #ifndef EXPORTSOWNERUID
  29. #define EXPORTSOWNERUID        ((uid_t) 0)
  30. #endif
  31. #ifndef EXPORTSOWNERGID
  32. #define EXPORTSOWNERGID        ((gid_t) 0)
  33. #endif
  34.  
  35. exportnode *export_list = NULL;
  36. int        allow_non_root = 0;
  37. int        promiscuous = 0;
  38. int        re_export = 0;
  39. int        trace_spoof = 1;
  40. int        auth_initialized = 0;
  41. int        have_setfsuid = 0;
  42.  
  43. static _PRO(int  filt_getc,    (FILE *)                    );
  44. static _PRO(int  getline,      (char **, FILE *)            );
  45. static _PRO(char *parse_opts,  (char *, char, nfs_mount *, char *)    );
  46. static _PRO(void parse_squash, (nfs_mount *mp, int uidflag, char **cpp)    );
  47. static _PRO(int  parse_num,    (char **cpp)                );
  48. static _PRO(void free_exports, (void)                    );
  49. #if 0
  50. static _PRO(char *h_strerror, (int));
  51. #endif
  52.  
  53. static int filt_getc(f)
  54. FILE *f;
  55. {
  56.     int c;
  57.  
  58.     c = getc(f);
  59.     if (c == '\\') {
  60.         c = getc(f);
  61.         if (c == '\n')
  62.             return (' ');
  63.         if (c != EOF)
  64.             ungetc(c, f);
  65.         return ('\\');
  66.     } else if (c == '#') {
  67.         int lastc = c;
  68.         while ((c = getc(f)) != '\n' && c != EOF)
  69.             lastc = c;
  70.         if (c == '\n' && lastc == '\\')
  71.             c = getc(f);
  72.     }
  73.     return (c);
  74. }
  75.  
  76. static int getline(lbuf, f)
  77. char **lbuf;
  78. FILE *f;
  79. {
  80.     register c;
  81.     register char *p;
  82.     char *buf;
  83.     int sz = CHUNK_SIZE;
  84.  
  85.     buf = (char *) xmalloc(sz);
  86.     p = buf;
  87.     while ((c = filt_getc(f)) != '\n' && c != EOF) {
  88.         if (p - buf == sz - 2) {
  89.             buf = (char *) xrealloc(buf, sz * 2);
  90.             p = buf + sz - 2;
  91.             sz *= 2;
  92.         }
  93.         *p++ = c;
  94.     }
  95.     if (c == EOF && p == buf) {
  96.         free(buf);
  97.         *lbuf = NULL;
  98.         return (0);
  99.     }
  100.     *p++ = '\0';
  101.     *lbuf = buf;
  102.     return (1);
  103. }
  104.  
  105. /*
  106.  * Parse number.
  107.  */
  108. static int parse_num(cpp)
  109. char    **cpp;
  110. {
  111.     char    *cp = *cpp, c;
  112.     int    num = 0;
  113.  
  114.     if (**cpp == '-')
  115.         (*cpp)++;
  116.     while (isdigit(**cpp))
  117.         (*cpp)++;
  118.     c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c;
  119.     return num;
  120. }
  121.  
  122. /*
  123.  * Install uid mapping records for a specified list of uids/gids.
  124.  * We first map these ids to the compile-time value AUTH_[UG]ID_NOBODY,
  125.  * which is later (in luid/lgid) mapped to the current nobody_uid/nobody_gid.
  126.  * We take these contortions because users may define option lists like this:
  127.  *
  128.  *    /foo        foo.bar.edu(squash=0-20,anonuid=32767)
  129.  *
  130.  * In this example, the squash list is parsed before we know what the anonuid
  131.  * really is.
  132.  */
  133. static void parse_squash(nfs_mount *mp, int uidflag, char **cpp)
  134. {
  135.     char    *cp = *cpp;
  136.     int    id0, id1;
  137.  
  138.     do {
  139.         id0 = parse_num(&cp);
  140.         if (*cp == '-') {
  141.             cp++;
  142.             id1 = parse_num(&cp);
  143.         } else {
  144.             id1 = id0;
  145.         }
  146.         if (uidflag) {
  147.             while (id0 <= id1)
  148.                 ugid_map_uid(mp, id0++, AUTH_UID_NOBODY);
  149.         } else {
  150.             while (id0 <= id1)
  151.                 ugid_map_gid(mp, id0++, AUTH_GID_NOBODY);
  152.         }
  153.         if (*cp != ',' || !isdigit(cp[1]))
  154.             break;
  155.         cp++;
  156.     } while(1);
  157.     *cpp = cp;
  158. }
  159.  
  160. /*
  161.  * Parse option string pointed to by s and set mount options accordingly.
  162.  */
  163. static char *parse_opts(cp, terminator, mp, client_name)
  164. char *cp;
  165. char terminator;
  166. nfs_mount *mp;
  167. char *client_name;
  168. {
  169.     char *kwd;
  170.     int  klen;
  171.  
  172.     /* skip white */
  173.     while (isspace(*cp))
  174.         cp++;
  175.     while (*cp != terminator) {
  176.         kwd = cp;
  177.         while (isalpha(*cp) || *cp == '_' || *cp == '=')
  178.             cp++;
  179.         klen = cp - kwd;
  180.  
  181.         /* process keyword */
  182.         if (strncmp(kwd, "secure", 6) == 0)
  183.             mp->o.secure_port = 1;
  184.         else if (strncmp(kwd, "insecure", 8) == 0)
  185.             mp->o.secure_port = 0;
  186.         else if (strncmp(kwd, "root_squash", 11) == 0)
  187.             mp->o.root_squash = 1;
  188.         else if (strncmp(kwd, "no_root_squash", 14) == 0)
  189.             mp->o.root_squash = 0;
  190.         else if (strncmp(kwd, "ro", 2) == 0)
  191.             mp->o.read_only = 1;
  192.         else if (strncmp(kwd, "rw", 2) == 0)
  193.             mp->o.read_only = 0;
  194.         else if (strncmp(kwd, "link_relative", 13) == 0)
  195.             mp->o.link_relative = 1;
  196.         else if (strncmp(kwd, "link_absolute", 13) == 0)
  197.             mp->o.link_relative = 0;
  198.         else if (strncmp(kwd, "map_daemon", 10) == 0)
  199.             mp->o.uidmap = map_daemon;
  200.         else if (strncmp(kwd, "map_identity", 12) == 0)
  201.             mp->o.uidmap = identity;
  202.         else if (strncmp(kwd, "all_squash", 10) == 0)
  203.             mp->o.all_squash = 1;
  204.         else if (strncmp(kwd, "no_all_squash", 13) == 0)
  205.             mp->o.all_squash = 0;
  206.         else if (strncmp(kwd, "noaccess", 8) == 0)
  207.             mp->o.noaccess = 1;
  208.         else if (strncmp(kwd, "squash_uids=", 12) == 0)
  209.             parse_squash(mp, 1, &cp);
  210.         else if (strncmp(kwd, "squash_gids=", 12) == 0)
  211.             parse_squash(mp, 0, &cp);
  212.         else if (strncmp(kwd, "anonuid=", 8) == 0)
  213.             mp->o.nobody_uid = parse_num(&cp);
  214.         else if (strncmp(kwd, "anongid=", 8) == 0)
  215.             mp->o.nobody_gid = parse_num(&cp);
  216.         else if (strncmp(kwd, "async", 5) == 0)
  217.             /* knfsd compatibility, ignore */;
  218.         else if (strncmp(kwd, "sync", 4) == 0)
  219.             /* knfsd compatibility, ignore */;
  220.         else {
  221.             dprintf(L_ERROR,
  222.                 "Unknown keyword \"%.*s\" in export file\n",
  223.                 klen, kwd);
  224.             mp->o.all_squash = 1;
  225.             mp->o.read_only = 1;
  226.         }
  227.         while (isspace(*cp))
  228.             cp++;
  229.         if (*cp == terminator)
  230.             break;
  231.         if (*cp == ',')
  232.             cp++;
  233.         else if (!isalpha(*cp) && *cp != '_' && *cp != '\0') {
  234.             if (client_name == NULL)
  235.                 dprintf(L_ERROR,
  236.                     "Comma expected in opt list for dflt clnt (found '%c')\n", *cp);
  237.             else
  238.                 dprintf(L_ERROR,
  239.                     "Comma expected in opt list for clnt %s (found '%c')\n",
  240.                     client_name, *cp);
  241.         }
  242.         while (isspace(*cp))
  243.             cp++;
  244.  
  245.         if (*cp == '\0' && *cp != terminator) {
  246.             dprintf(L_ERROR,
  247.                 "missing terminator \"%c\" on option list\n",
  248.                 terminator);
  249.             return (cp);
  250.         }
  251.     }
  252.     if (*cp != terminator)
  253.         dprintf(L_ERROR, "Trouble in parser, character '%c'.\n", *cp);
  254.  
  255.     cp++;            /* Skip past terminator */
  256.     while (isspace(*cp))
  257.         cp++;
  258.     return (cp);
  259. }
  260.  
  261. static nfs_client *get_client(hname)
  262. char *hname;
  263. {
  264.     nfs_client *cp;
  265.  
  266.     if (hname && *hname == '\0')
  267.         hname = NULL;
  268.     if ((cp = auth_get_client(hname)) == NULL)
  269.         cp = auth_create_client(hname, NULL);
  270.  
  271.     return cp;
  272. }
  273.  
  274. void auth_init(fname)
  275. char *fname;
  276. {
  277.     exportnode    *resex;        /* export data for showmount -x */
  278.     groupnode    *resgr;
  279.     static char    *auth_file = NULL;
  280.     FILE        *ef;
  281.     char        *cp;        /* Current line position */
  282.     char        *sp;        /* Secondary pointer */
  283.     char        *fs_name;
  284.     char        path[PATH_MAX];
  285.     char        resolved_path[PATH_MAX];
  286.  
  287.     if (auth_initialized) {
  288.         free_exports();
  289.         fname = auth_file;
  290.     }
  291.  
  292.     auth_init_lists();
  293.  
  294.     if (fname == NULL)
  295.         fname = EXPORTSFILE;
  296.     auth_file = fname;    /* Save for re-initialization */
  297.  
  298.     /* Check protection of exports file. */
  299.     switch(iCheckAccess(auth_file, EXPORTSOWNERUID, EXPORTSOWNERGID)) {
  300.     case FACCESSWRITABLE:
  301.         dprintf(L_ERROR,
  302.             "SECURITY: A user with uid != %d can write to %s!\n",
  303.                 EXPORTSOWNERUID, fname);
  304.         dprintf(L_ERROR, "exiting because of security violation.\n");
  305.         exit(1);
  306.     case FACCESSBADOWNER:
  307.         dprintf(L_ERROR,
  308.             "SECURITY: File %s not owned by uid %d/gid %d!\n",
  309.                 fname, EXPORTSOWNERUID, EXPORTSOWNERGID);
  310.         dprintf(L_ERROR, "exiting because of security violation.\n");
  311.         exit(1);
  312.     }
  313.  
  314.     if ((ef = fopen(fname, "r")) == NULL) {
  315.         dprintf(L_ERROR, "Could not open exports file %s: %s\n",
  316.             fname, strerror(errno));
  317.         exit(1);
  318.     }
  319.     while (getline(&cp, ef)) {
  320.         char *saved_line = cp;    /* For free()ing it later. */
  321.         char *mount_point, *host_name, cc;
  322.         nfs_client *clnt;
  323.         nfs_mount *mnt;
  324.  
  325.         while (isspace(*cp))
  326.             cp++;
  327.  
  328.         /* Check for "empty" lines. */
  329.         if (*cp == '\0')
  330.             continue;
  331.  
  332.         /* Get the file-system name. */
  333.         fs_name = cp;
  334.         while (*cp != '\0' && !isspace(*cp))
  335.             cp++;
  336.         for (sp = path; fs_name < cp;)
  337.             *sp++ = *fs_name++;
  338.         *sp = '\0';
  339.  
  340.         /* Make sure it's symlink-free, if possible. */
  341.         if (realpath(path, resolved_path) == NULL)
  342.             strcpy(resolved_path, path);
  343.  
  344.         /* Copy it into a new string. */
  345.         mount_point = xstrdup(resolved_path);
  346.  
  347.         /* Build the RPC mount export list data structure. */
  348.         resex = (exportnode *) xmalloc(sizeof *resex);
  349.         resex->ex_dir = mount_point;
  350.         resex->ex_groups = NULL;
  351.  
  352.         while (isspace(*cp))
  353.             cp++;
  354.  
  355. #ifndef NEW_STYLE_EXPORTS_FILE
  356.         /* Special case for anononymous NFS. */
  357.         if (*cp == '\0') {
  358.             clnt = get_client(NULL);
  359.             mnt = auth_add_mount(clnt, mount_point);
  360.         }
  361.         while (*cp != '\0') {
  362.             host_name = cp;
  363.  
  364.             /* Host name. */
  365.             while (*cp != '\0' && !isspace(*cp) && *cp != '(')
  366.                 cp++;
  367.             cc = *cp; *cp = '\0';
  368.             clnt = get_client(host_name);
  369.             *cp = cc;
  370.  
  371.             mnt = auth_add_mount(clnt, mount_point);
  372.  
  373.             /* Finish parsing options. */
  374.             while (isspace(*cp))
  375.                 cp++;
  376.             if (*cp == '(')
  377.                 cp = parse_opts(cp + 1, ')', mnt,
  378.                         clnt->clnt_name);
  379.  
  380.             /* For anon exports, resex->ex_groups should be
  381.              * NULL */
  382.             if (!mnt->o.noaccess && clnt->clnt_name) {
  383.                 resgr = (groupnode *) xmalloc(sizeof(*resgr));
  384.                 resgr->gr_name = clnt->clnt_name;
  385.                 resgr->gr_next = resex->ex_groups;
  386.                 resex->ex_groups = resgr;
  387.             }
  388.         }
  389. #endif
  390.         resex->ex_next = export_list;
  391.         export_list = resex;
  392.  
  393.         free(saved_line);
  394.     }
  395.     fclose(ef);
  396.  
  397.     if (promiscuous) {
  398.         auth_create_default_client();
  399.     }
  400.  
  401.     /* Finally, resolve any mount points for netgroup and wildcard
  402.      * hosts that apply to known hosts as well.
  403.      */
  404.     auth_check_all_netmasks();
  405.     auth_check_all_netgroups();
  406.     auth_check_all_wildcards();
  407.  
  408. #if defined(MAYBE_HAVE_SETFSUID) && !defined(HAVE_SETFSUID)
  409.     /* check if the a.out setfsuid syscall works on this machine */
  410.     have_setfsuid = (setfsuid(0) >= 0);
  411. #endif
  412.  
  413.     auth_initialized = 1;
  414. }
  415.  
  416. /* 
  417.  * Clear the export list.
  418.  */
  419. static void
  420. free_exports()
  421. {
  422.     exportnode    *ex, *nex;
  423.     groupnode    *gr, *ngr;
  424.  
  425.     for (ex = export_list; ex != NULL; ex = nex) {
  426.         nex = ex->ex_next;
  427.         free (ex->ex_dir);
  428.         for (gr = ex->ex_groups; gr != NULL; gr = ngr) {
  429.             ngr = gr->gr_next;
  430.             /* gr->gr_name has already been freed in auth.c */
  431.             free (gr);
  432.         }
  433.         free (ex);
  434.     }
  435.     export_list = NULL;
  436. }
  437.  
  438. #if 0
  439. static char *h_strerror(errnum)
  440. int errnum;
  441. {
  442.     char *reason;
  443.  
  444.     switch (h_errno) {
  445. #ifdef HOST_NOT_FOUND        /* Only on BSD 4.3 and compatible systems. */
  446.     case HOST_NOT_FOUND:
  447.         reason = "Authoritative -- the host exists only in your imagination.";
  448.         break;
  449.     case TRY_AGAIN:
  450.         reason = "Non-Authoritative -- the host might exist.";
  451.         break;
  452.     case NO_RECOVERY:
  453.         reason = "Non-recoverable error.";
  454.         break;
  455.     case NO_ADDRESS:
  456.         reason = "Valid host name, but no address.";
  457.         break;
  458. #endif
  459.     default:
  460.         reason = "Unknown reason.";
  461.     }
  462.     return reason;
  463. }
  464. #endif
  465.